package http

import (
	"encoding/json"
	"net/http"
	"net/http/cookiejar"
	"strings"
	"net/url"
	"io"
	"bytes"
)

type Request struct {
	Url          string         // request url
	Method       string         // request method
	SpiderName   string         // spider name
	CallBackName string         // response after call func name
	BodyType     string         // request body type: json/form
	BodyValues   interface{}    // request body: map
	Cookies      []*http.Cookie // cookie
	Header       http.Header    // request header
	ProxyAddr    string         // proxy address eg: http://111.111.111.11:8090
	Seen         string         // request seen
}

// make request
func NewRequest(method string, url string) (*Request, error) {
	req := new(Request)
	req.Url = url
	req.Method = strings.ToUpper(method)
	req.Header = make(map[string][]string)
	return req, nil
}

func (r *Request) Do() (*Response, error) {
	var (
		err      error
		body     io.Reader
		client   *http.Client
		request  *http.Request
		response *http.Response
	)
	// post body
	if r.Method == http.MethodPost && r.BodyValues != nil {
		switch r.BodyType {
		case "json":
			// json body
			r.Header.Set("Content-Type", "application/json")
			if bs, err := json.Marshal(r.BodyValues); err != nil {
				return nil, err
			} else {
				body = bytes.NewReader(bs)
			}
		case "form":
			r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
			// form body
			if values, ok := r.BodyValues.(url.Values); ok {
				body = strings.NewReader(values.Encode())
			}
		}
	} else {
		body = nil
	}

	// create go request
	if request, err = http.NewRequest(r.Method, r.Url, body); err != nil {
		return nil, err
	}

	// set request header
	request.Header = r.Header

	// create http client
	client = &http.Client{}

	// set client cookie
	if r.Cookies != nil {
		jar, _ := cookiejar.New(nil)
		jar.SetCookies(request.URL, r.Cookies)
		client.Jar = jar
	}

	// set client proxy
	if r.ProxyAddr != "" {
		t := new(http.Transport)
		t.Proxy = func(request *http.Request) (*url.URL, error) {
			return url.Parse(r.ProxyAddr)
		}
		client.Transport = t
	}

	// request
	response, err = client.Do(request)

	if err != nil {
		return nil, err
	}
	return NewResponse(r, response), nil
}

func (r *Request) SetHeader(key string, value string) *Request {
	r.Header.Add(key, value)
	return r
}

// set request cookie
func (r *Request) SetCookie(cookies []*http.Cookie) *Request {
	r.Cookies = cookies
	return r
}

// set request proxy
func (r *Request) SetProxy(proxy string) *Request {
	r.ProxyAddr = proxy
	return r
}

// set request body
func (r *Request) SetBody(t string, values interface{}) *Request {
	r.BodyValues = &values
	r.BodyType = t
	return r
}

func (r *Request) Marshal() (bs []byte, err error) {
	return json.Marshal(r)
}

func Serialize(r *Request) {
	//s := struct {
	//	Url          string
	//	Method       string
	//	SpiderName   string
	//	CallBackName string
	//}{}
}

func UnSerialize() {

}
